package com.panda.web.controller.wechat;

import com.aliyun.apache.hc.client5.http.classic.methods.HttpGet;
import com.aliyun.apache.hc.client5.http.classic.methods.HttpPost;
import com.aliyun.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import com.aliyun.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import com.aliyun.apache.hc.client5.http.impl.classic.HttpClients;
import com.aliyun.apache.hc.core5.http.ContentType;
import com.aliyun.apache.hc.core5.http.HttpEntity;
import com.aliyun.apache.hc.core5.http.io.entity.EntityUtils;
import com.aliyun.apache.hc.core5.http.io.entity.StringEntity;
import com.panda.common.core.controller.BaseController;
import com.panda.common.core.domain.R;
import com.panda.web.entity.wechat.WechatGzh;
import com.panda.web.entity.wechat.WechatUser;
import com.panda.web.mapper.wechat.WechatGzhMapper;
import com.panda.web.mapper.wechat.WechatUserMapper;
import com.panda.web.utils.WXBizMsgCrypt;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.checkerframework.checker.units.qual.A;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 微信回调Controller
 *
 * @author cpanda
 * @date 2025-02-21
 */
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/wechatCallback")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class WeChatCallbackController extends BaseController {
    @Autowired
    WechatGzhMapper gzhMapper;
    @Autowired
    WechatUserMapper userMapper;
    @Autowired
    private WXBizMsgCrypt msgCrypt; // 注入解密工具
    private static final String TOKEN = "MyWechatToken626"; // 替换为实际Token
    private static final String APP_ID = "wx83de228493c38c1c"; // 替换为实际AppID
    private static final String APP_SECRET = "c9722f9217d91fda34f8667a56ae563b"; // 替换为实际AppSecret

    // 存储access_token及其过期时间
    private String accessToken = "";
    private long tokenExpireTime = 0;

    // 存储用户信息（实际应用中应使用数据库）
    private Map<String, Map<String, String>> userStore = new HashMap<>();

    /**
     * 微信服务器验证接口
     */
    /**
     * 验证服务器有效性（GET请求）
     */
    @GetMapping
    public ResponseEntity<String> validateWechat(
            @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp,
            @RequestParam("nonce") String nonce,
            @RequestParam("echostr") String echostr) {

        System.out.println("\n=== 微信验证请求 ===");
        System.out.println("Signature: " + signature);
        System.out.println("Timestamp: " + timestamp);
        System.out.println("Nonce: " + nonce);

        if (checkSignature(signature, timestamp, nonce)) {
            return new ResponseEntity<>(echostr, HttpStatus.OK);
        }
        return new ResponseEntity<>("Invalid signature", HttpStatus.FORBIDDEN);
    }
    /**
     * 验证签名
     */
    private boolean checkSignature(String signature, String timestamp, String nonce) {
        // 1. 字典序排序
        String[] arr = new String[]{TOKEN, timestamp, nonce};
        Arrays.sort(arr);

        // 2. 拼接字符串
        String joined = String.join("", arr);

        // 3. SHA1加密
        String calculatedSignature = DigestUtils.sha1Hex(joined);

        // 4. 调试输出
        System.out.println("计算签名: " + calculatedSignature);
        System.out.println("微信签名: " + signature);

        return calculatedSignature.equals(signature);
    }
    /**
     * 处理所有消息（POST）
     */
    @PostMapping
    public ResponseEntity<String> handleEvent(
            @RequestParam("signature") String signature,
            @RequestParam("timestamp") String timestamp,
            @RequestParam("nonce") String nonce,
            @RequestBody String requestBody) {

        System.out.println("\n=== 明文模式收到消息 ===");
        System.out.println("原始XML:\n" + requestBody);

        try {
            // 1. 强制签名验证
            if (!checkSignature(signature, timestamp, nonce)) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Invalid signature");
            }

            // 2. 解析XML
            Map<String, String> msgMap = parseXml(requestBody);
            String msgType = msgMap.get("MsgType");
            String event = msgMap.get("Event");


            // 处理关注事件
            if ("event".equals(msgType) && "subscribe".equals(event)) {
                return handleSubscribeEvent(msgMap);
            }

            // 处理取消关注事件
            if ("event".equals(msgType) && "unsubscribe".equals(event)) {
                return handleUnsubscribeEvent(msgMap);
            }

            // 处理文本消息（用于测试）
            if ("text".equals(msgType)) {
                return handleTextMessage(msgMap);
            }

            // 默认响应
            return new ResponseEntity<>("success", HttpStatus.OK);

        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>("error", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 处理关注事件
     */
    private ResponseEntity<String> handleSubscribeEvent(Map<String, String> msgMap) {
        String openid = msgMap.get("FromUserName");
        System.out.println("用户关注: " + openid);

        // 获取用户信息（包含unionid）
        JSONObject userInfo = getUserInfo(openid);
        if (userInfo != null) {
            String unionid = userInfo.optString("unionid", "未获取到unionid");
            String nickname = userInfo.optString("nickname", "未知用户");

            System.out.println("获取用户信息成功: ");
            System.out.println("OpenID: " + openid);
            System.out.println("UnionID: " + unionid);
            System.out.println("昵称: " + nickname);
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
//            WechatUser wechatUser = userMapper.findByOfficialOpenid(openid);
            WechatUser wechatUser = userMapper.findByUnionidOpenid(unionid);
            if (wechatUser!=null){
                wechatUser.setFollowStatus("1");
                wechatUser.setOfficialOpenid(openid);
                userMapper.updateById(wechatUser);
            }
            WechatGzh wechatGzh = gzhMapper.findByOpenid(openid);
            if (wechatGzh!=null){//说已关注公众号已存在，进行修改 不在新增
                wechatGzh.setUnionid(unionid);
                wechatGzh.setNickname(nickname);
                wechatGzh.setTurnoverTime(time);
                gzhMapper.updateById(wechatGzh);
            }else {
                // 新用户：创建新对象
                wechatGzh = new WechatGzh(); // 必须实例化！
                wechatGzh.setOpenid(openid); // 必须设置openid
                wechatGzh.setUnionid(unionid);
                wechatGzh.setNickname(nickname);
                wechatGzh.setCreationTime(time);
                wechatGzh.setTurnoverTime(time);
                gzhMapper.insert(wechatGzh);
            }
            // 发送欢迎消息
            return buildTextResponse(msgMap, "感谢关注：职到了公众平台！");
        }

        return buildTextResponse(msgMap, "感谢关注！获取用户信息失败，请稍后再试。");
    }

    /**
     * 处理取消关注事件
     */
    private ResponseEntity<String> handleUnsubscribeEvent(Map<String, String> msgMap) {
        String openid = msgMap.get("FromUserName");
        System.out.println("用户取消关注: " + openid);
        //TODO 根据 公众号openid 去找用户表存不存在该用户，存在 状态修改为0
        WechatUser wechatUser = userMapper.findByOfficialOpenid(openid);
        if (wechatUser!=null){
            wechatUser.setFollowStatus("0");
            userMapper.updateById(wechatUser);
        }
        gzhMapper.deleteByOpenid(openid);

        return new ResponseEntity<>("success", HttpStatus.OK);
    }

    /**
     * 处理文本消息（用于测试）
     */
    private ResponseEntity<String> handleTextMessage(Map<String, String> msgMap) {
        String content = msgMap.get("Content");
        String openid = msgMap.get("FromUserName");

        // 查询用户信息命令
        if ("info".equalsIgnoreCase(content)) {
            if (userStore.containsKey(openid)) {
                Map<String, String> userData = userStore.get(openid);
                return buildTextResponse(msgMap, "您的信息:\nOpenID: " + userData.get("openid") +
                        "\nUnionID: " + userData.get("unionid") +
                        "\n昵称: " + userData.get("nickname"));
            }
            return buildTextResponse(msgMap, "未找到您的用户信息");
        }

        // 帮助命令
        if ("help".equalsIgnoreCase(content)) {
            return buildTextResponse(msgMap, "可用命令:\ninfo - 查看用户信息\nhelp - 帮助信息");
        }

        // 默认回复
        return buildTextResponse(msgMap, "收到消息: " + content + "\n发送 'info' 查看您的信息");
    }

    /**
     * 解析XML为Map
     */
    private Map<String, String> parseXml(String xml) throws Exception {
        Map<String, String> map = new HashMap<>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(xml)));

        NodeList nodes = doc.getDocumentElement().getChildNodes();
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                map.put(node.getNodeName(), node.getTextContent());
            }
        }
        return map;
    }

    /**
     * 获取用户信息（包含unionid）
     */
    private JSONObject getUserInfo(String openid) {
        try {
            String token = getAccessToken();
            if (token == null) {
                System.err.println("无法获取Access Token");
                return null;
            }

            String url = "https://api.weixin.qq.com/cgi-bin/user/info" +
                    "?access_token=" + token +
                    "&openid=" + openid +
                    "&lang=zh_CN";

            System.out.println("请求用户信息URL: " + url);

            try (CloseableHttpClient httpClient = HttpClients.createDefault();
                 CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {

                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity);
                System.out.println("用户信息响应: " + result);

                JSONObject json = new JSONObject(result);

                if (json.has("errcode") && json.getInt("errcode") != 0) {
                    System.err.println("获取用户信息失败: " + json);
                    return null;
                }

                return json;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取公众号Access Token
     */
    private synchronized String getAccessToken() {
        // 检查token是否过期（提前5分钟刷新）
        if (accessToken != null && !accessToken.isEmpty() &&
                System.currentTimeMillis() < tokenExpireTime - 300000) {
            System.out.println("使用缓存Access Token: " + accessToken);
            return accessToken;
        }

        try {
            String url = "https://api.weixin.qq.com/cgi-bin/token" +
                    "?grant_type=client_credential" +
                    "&appid=" + APP_ID +
                    "&secret=" + APP_SECRET;

            System.out.println("请求Access Token URL: " + url);

            try (CloseableHttpClient httpClient = HttpClients.createDefault();
                 CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {

                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity);
                System.out.println("Access Token响应: " + result);

                JSONObject json = new JSONObject(result);

                if (json.has("access_token")) {
                    accessToken = json.getString("access_token");
                    // 设置token过期时间（微信默认7200秒）
                    tokenExpireTime = System.currentTimeMillis() + json.getLong("expires_in") * 1000;
                    System.out.println("获取新Access Token: " + accessToken +
                            ", 过期时间: " + new Date(tokenExpireTime));
                    return accessToken;
                } else {
                    System.err.println("获取Access Token失败: " + json);
                    return null;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 构建文本消息回复
     */
    private ResponseEntity<String> buildTextResponse(Map<String, String> msgMap, String content) {
        String fromUser = msgMap.get("ToUserName");
        String toUser = msgMap.get("FromUserName");
        long createTime = System.currentTimeMillis() / 1000;

        String response = "<xml>" +
                "<ToUserName><![CDATA[" + toUser + "]]></ToUserName>" +
                "<FromUserName><![CDATA[" + fromUser + "]]></FromUserName>" +
                "<CreateTime>" + createTime + "</CreateTime>" +
                "<MsgType><![CDATA[text]]></MsgType>" +
                "<Content><![CDATA[" + content + "]]></Content>" +
                "</xml>";

        System.out.println("回复消息: \n" + response);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    /**
     * 测试接口：查看所有存储的用户
     */
    @GetMapping("/users")
    public ResponseEntity<List<Map<String, String>>> getAllUsers() {
        return new ResponseEntity<>(new ArrayList<>(userStore.values()), HttpStatus.OK);
    }

    /**
     * 测试接口：查看Access Token状态
     */
    @GetMapping("/token")
    public ResponseEntity<Map<String, Object>> getTokenStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("accessToken", accessToken);
        status.put("expireTime", new Date(tokenExpireTime));
        status.put("isValid", tokenExpireTime > System.currentTimeMillis());
        return new ResponseEntity<>(status, HttpStatus.OK);
    }

    /**
     * 获取所有关注该公众号的用户
     */
    @GetMapping("/gzh/gz")
    private R setGzhUionId() throws Exception {
        String accessToken = getAccessToken();  //获取的微信公众号的access_token
        List<String> stringList = getAllSubscribedOpenIds(accessToken);
        List<JSONObject> jsonObjects = batchGetUserInfos(accessToken,stringList);
        for (JSONObject jsonObject : jsonObjects) {
            String openid = jsonObject.getString("openid");
            String unionid = jsonObject.getString("unionid");
            WechatUser wechatUser = userMapper.findByOfficialOpenid(openid);
            if (wechatUser!=null){
                wechatUser.setUnionid(unionid);
                userMapper.updateById(wechatUser);
            }

        }
        return R.ok(1,200,"ok");
    }

    /**
     * 获取所有关注用户的OpenID列表
     */
    private static List<String> getAllSubscribedOpenIds(String accessToken) throws Exception {
        List<String> openIds = new ArrayList<>();
        String nextOpenId = "";

        do {
            String url = "https://api.weixin.qq.com/cgi-bin/user/get" +
                    "?access_token=" + accessToken +
                    "&next_openid=" + nextOpenId;

            try (CloseableHttpClient httpClient = HttpClients.createDefault();
                 CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {

                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity);
                JSONObject json = new JSONObject(result);

                if (json.has("data") && json.getJSONObject("data").has("openid")) {
                    JSONArray openidArray = json.getJSONObject("data").getJSONArray("openid");
                    for (int i = 0; i < openidArray.length(); i++) {
                        openIds.add(openidArray.getString(i));
                    }
                }

                // 检查是否有下一页
                nextOpenId = json.optString("next_openid", "");

            } catch (Exception e) {
                e.printStackTrace();
                break;
            }

        } while (!nextOpenId.isEmpty());

        return openIds;
    }

    /**
     * 批量获取用户详细信息（每次最多100个）
     */
    private static List<JSONObject> batchGetUserInfos(String accessToken, List<String> openIds) throws Exception {
        List<JSONObject> userInfos = new ArrayList<>();
        String url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=" + accessToken;

        // 微信API限制每次最多查询100个用户
        int batchSize = 100;
        int totalUsers = openIds.size();

        for (int i = 0; i < totalUsers; i += batchSize) {
            int end = Math.min(i + batchSize, totalUsers);
            List<String> batch = openIds.subList(i, end);

            // 构建请求体
            JSONObject requestBody = new JSONObject();
            JSONArray userList = new JSONArray();

            for (String openid : batch) {
                JSONObject user = new JSONObject();
                user.put("openid", openid);
                user.put("lang", "zh_CN"); // 语言设置
                userList.put(user);
            }

            requestBody.put("user_list", userList);

            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpPost httpPost = new HttpPost(url);
                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setEntity(new StringEntity(requestBody.toString(), ContentType.parse("UTF-8")));

                try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                    HttpEntity entity = response.getEntity();
                    String result = EntityUtils.toString(entity);
                    JSONObject json = new JSONObject(result);

                    if (json.has("user_info_list")) {
                        JSONArray infoList = json.getJSONArray("user_info_list");
                        for (int j = 0; j < infoList.length(); j++) {
                            userInfos.add(infoList.getJSONObject(j));
                        }
                    } else {
                        System.err.println("批量获取用户信息失败: " + json);
                    }
                }
            }
        }

        return userInfos;
    }
}
